package com.zsummer.baikal.common.config.security;

import cn.hutool.core.util.StrUtil;
import com.zsummer.baikal.common.constant.Constants;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

/**
 * jwt认证
 *
 * @author zsummer
 * @since 2021/7/28
 */
@Component
@RequiredArgsConstructor
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    private final TokenManager tokenManager;

    private final RedisTemplate redisTemplate;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        String authorization = request.getHeader(Constants.HEAD_AUTH);
        if (StrUtil.startWith(authorization, TokenManager.BEARER)) {
            try {
                String jwt = StrUtil.removePrefix(authorization, TokenManager.BEARER);
                String username = tokenManager.getUserName(jwt);
                // 从redis中获取权限
                List<GrantedAuthority> authorities = (List<GrantedAuthority>) redisTemplate.opsForHash().get(Constants.REDIS_KEY_USER_PERM, username);
                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(username, jwt, authorities);
                authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                // 将用户添加到上下文
                SecurityContextHolder.getContext().setAuthentication(authentication);
            } catch (Exception e) {
                SecurityContextHolder.clearContext();
            }
        }
        chain.doFilter(request, response);
    }
}
